package com.hqd.jjvm.rtda;

import com.hqd.jjvm.rtda.obj.JObject;
import com.hqd.jjvm.rtda.slot.NumberSlot;
import com.hqd.jjvm.rtda.slot.RefSlot;
import com.hqd.jjvm.rtda.slot.Slot;
import lombok.Getter;

import java.util.Stack;

/**
 * 操作栈
 */
@Getter
public class OperandStack {
    private int size;
    private Stack<Slot> stack;

    public OperandStack(int size) {
        if (size > 0) {
            stack = new Stack();
        }
    }

    public void pushInt(int val) {
        push(new NumberSlot(val));
    }

    public Integer popInt() {
        return ((Number) pop().getVal()).intValue();
    }


    public void pushFloat(Float val) {
        push(new NumberSlot(val));
    }

    public Float popFloat() {
        return ((Number) pop().getVal()).floatValue();
    }

    public void pushLong(long val) {
        push(new NumberSlot(val));
        push(new NumberSlot(0L));
    }

    public Long popLong() {
        long num1 = ((Number) pop().getVal()).longValue();
        long num2 = ((Number) pop().getVal()).longValue();
        return num1 + num2;
    }

    public void pushDouble(Double val) {
        push(new NumberSlot(val));
        push(new NumberSlot(0.0D));
    }

    public Double popDouble() {
        double num1 = ((Number) pop().getVal()).doubleValue();
        double num2 = ((Number) pop().getVal()).doubleValue();
        return num1 + num2;
    }

    public void pushRef(JObject ref) {
        push(new RefSlot(ref));
    }

    public JObject popRef() {
        return (JObject) pop().getVal();
    }

    public Slot pop() {
        return stack.pop();
    }

    public Object popVal() {
        size--;
        Slot slot = stack.peek();
        if (slot instanceof NumberSlot) {
            if (slot.getVal() instanceof Long) {
                size--;
                return popLong();
            } else if (slot.getVal() instanceof Double) {
                size--;
                return popDouble();
            }
        }
        return stack.pop().getVal();
    }

    public Object peekVal() {
        return stack.peek().getVal();
    }

    public JObject peekRefVal() {
        return (JObject) peekVal();
    }

    public void push(Slot slot) {
        stack.push(slot);
        size++;
    }
}
